/*
 * Copyright (C) 2024-2025 Deepin Technology Co., Ltd.
 *
 * Author:     zhangbingyi <zhangbingyi@uniontech.com>
 *
 * Maintainer: zhangbingyi <zhangbingyi@uniontech.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "securitytoolsmodel.h"
#include "common.h"
#include "gsettingkey.h"
#include "invokers/invokerfactory.h"
#include "securitytools/trustedprotection/trustedprotectiondefinition.h"
#include "dversionnumber.h"

#include <QDebug>
#include <QProcess>


#include <pwd.h>
#include <unistd.h>

#define IMA_NAME "com.deepin.daemon.ImaDaemon"
#define IMA_PATH "/com/deepin/daemon/ImaDaemon"
#define IMA_INTERFACE "com.deepin.daemon.ImaDaemon"

SecurityToolsModel::SecurityToolsModel(QObject *parent)
    : QObject(parent)
    , m_dataInterDbusInvoker(nullptr)
    , m_imaDbusInvoker(nullptr)
    , m_isLevelShow(false)
    , m_isValidSecurityEnhance(false)
    , m_systemLevelDBusInter(nullptr)
    , m_gsetting(nullptr)
    , m_exeFilesDBusInter(nullptr)
    , m_accountsDBusInter(nullptr)
    , m_peripheralsDBusInter(nullptr)
    , m_policyManagerDBusInter(nullptr)
    , m_rootSystemDBusInter(nullptr)
{
    // 初始化数据
    initData();
    getExeFilesStatus();
}

SecurityToolsModel::~SecurityToolsModel()
{
}

// 资源管理接口是否可用
bool SecurityToolsModel::isResourceManagerValid()
{
    return m_isResourceManagerValid;
}

// 获取ima状态
int SecurityToolsModel::getIMAStatus()
{
    int imaStatus = IMAStatusUnknow;
    QDBusMessage msg = m_imaDbusInvoker->Invoke("GetState");
    if (msg.errorMessage().isEmpty()) {
        GET_MESSAGE_VALUE(int, status, msg);
        imaStatus = status;
    }
    return imaStatus;
}

// 获取执行保护模块状态
bool SecurityToolsModel::getExeFilesStatus()
{
    bool isExeFilesStatus = false;
    QDBusMessage msg = DBUS_BLOCK_INVOKE(m_exeFilesDBusInter, DBUS_PROPERTY_INVOKER_NAME, "Availabled");
    if (QDBusMessage::MessageType::ErrorMessage == msg.type()) {
        qDebug() << Q_FUNC_INFO << msg.errorMessage();
    } else {
        QVariant ret = msg.arguments().first();
        // 将QDbusVariant转成QVariant
        ret = Utils::checkAndTransQDbusVarIntoQVar(ret);
        isExeFilesStatus = ret.toBool();
    }
    return isExeFilesStatus;
}

// 是否允许进行外设管控
bool SecurityToolsModel::isAllowPeripheralsManage()
{
    bool isPeripheralsManageStatus = false;
    QDBusMessage msg = DBUS_BLOCK_INVOKE(m_peripheralsDBusInter, DBUS_PROPERTY_INVOKER_NAME, "Availabled");
    if (QDBusMessage::MessageType::ErrorMessage == msg.type()) {
        qDebug() << Q_FUNC_INFO << msg.errorMessage();
    } else {
        QVariant ret = msg.arguments().first();
        // 将QDbusVariant转成QVariant
        ret = Utils::checkAndTransQDbusVarIntoQVar(ret);
        isPeripheralsManageStatus = ret.toBool();
    }
    return isPeripheralsManageStatus;
}

// 是否显示外设管控入口
bool SecurityToolsModel::isShowPeripheralManage()
{
    return m_gsetting->GetValue(PERIPHERALS_MANAGEMENGT_WIDGET_SHOW).toBool();
}

// selinux是否开启
bool SecurityToolsModel::isSelinuxOpen()
{
    bool isSelinuxOpenStatus = false;
    QDBusMessage msg = DBUS_BLOCK_INVOKE(m_policyManagerDBusInter, "GetSecurityStatus");
    if (QDBusMessage::MessageType::ErrorMessage == msg.type()) {
        qDebug() << Q_FUNC_INFO << msg.errorMessage();
    } else {
        GET_MESSAGE_VALUE(bool, status, msg);
        isSelinuxOpenStatus = status;
    }
    return isSelinuxOpenStatus;
}

// 开启selinux
void SecurityToolsModel::oepnSelinux()
{
    QDBusMessage msg = DBUS_BLOCK_INVOKE(m_policyManagerDBusInter, "EnableSecurity");
    if (QDBusMessage::MessageType::ErrorMessage == msg.type()) {
        qDebug() << Q_FUNC_INFO << msg.errorMessage();
    } else {
        // 重启系统
        DBUS_NOBLOCK_INVOKE(m_rootSystemDBusInter, "RequestReboot");
    }
}

void SecurityToolsModel::initData()
{
    m_dataInterDbusInvoker = InvokerFactory::GetInstance().CreateInvoker("com.deepin.defender.datainterface",
                                                                         "/com/deepin/defender/datainterface",
                                                                         "com.deepin.defender.datainterface",
                                                                         ConnectType::SESSION, this);

    m_imaDbusInvoker = InvokerFactory::GetInstance().CreateInvoker(IMA_NAME,
                                                                   IMA_PATH,
                                                                   IMA_INTERFACE,
                                                                   ConnectType::SYSTEM, this);

    m_exeFilesDBusInter = InvokerFactory::GetInstance().CreateInvoker("com.deepin.daemon.ACL",
                                                                      "/org/desktopspec/Guard/Integrity1",
                                                                      "org.desktopspec.GuardIntegrity1",
                                                                      ConnectType::SYSTEM, this);

    // 获取资源管控dbus接口状态
    QDBusMessage msg = DBUS_BLOCK_INVOKE(m_dataInterDbusInvoker, "GetUosResourceStatus");
    GET_MESSAGE_VALUE(bool, status, msg);
    m_isResourceManagerValid = status;

    m_systemLevelDBusInter = InvokerFactory::GetInstance().CreateInvoker("com.deepin.defender.MonitorNetFlow",
                                                                         "/com/deepin/defender/systemlevel",
                                                                         "com.deepin.defender.systemlevel",
                                                                         ConnectType::SYSTEM, this);
    // 获取等保开启状态
    QDBusMessage msgLevel = DBUS_BLOCK_INVOKE(m_systemLevelDBusInter, "QuerySystemLevelStatus");
    GET_MESSAGE_VALUE(QString, sStatus, msgLevel);
    m_sLevelStatus = sStatus;

    // 获取系统安全等级界面显示gsetting设置
    m_gsetting = InvokerFactory::GetInstance().CreateSettings("com.deepin.dde.deepin-defender", QByteArray(), this);

    // 获取等保
    QString sSecurityEnhance = "dpkg -s deepin-security-enhance | grep Version";
    QProcess *processSSH = new QProcess(this);
    processSSH->start(sSecurityEnhance);
    processSSH->waitForStarted();
    processSSH->waitForFinished();
    QString sSecurityEnhanceInfo = QString::fromLocal8Bit(processSSH->readAllStandardOutput()).trimmed();
    processSSH->close();
    processSSH->deleteLater();

    QString sVersion;
    QStringList sSecurityEnhanceInfoList = sSecurityEnhanceInfo.split("\n");
    for (int i = 0; i < sSecurityEnhanceInfoList.count(); ++i) {
        if (sSecurityEnhanceInfoList.at(i).contains("Version:")) {
            QStringList sVersionList = sSecurityEnhanceInfoList.at(i).split(":");
            if (sVersionList.count() >= 2) {
                sVersion = sVersionList.at(1).trimmed();
            }
        }
    }

    if (sVersion.isEmpty()) {
        m_isValidSecurityEnhance = false;
    } else {
        m_isValidSecurityEnhance = DVersionNumber::compare(DVersionNumber::fromString(sVersion), DVersionNumber::fromString(QString("1.1.3-1"))) > 0;
    }

    m_accountsDBusInter = InvokerFactory::GetInstance().CreateInvoker("org.freedesktop.Accounts",
                                                                      "/org/freedesktop/Accounts",
                                                                      "org.freedesktop.Accounts",
                                                                      ConnectType::SYSTEM, this);

    // 创建外设管理服务对象
    m_peripheralsDBusInter = InvokerFactory::GetInstance().CreateInvoker("org.deepin.PermissionManager",
                                                                         "/org/deepin/PermissionManager/DeviceProtect",
                                                                         "org.deepin.PermissionManager.DeviceProtect",
                                                                         ConnectType::SYSTEM, this);

    m_policyManagerDBusInter = InvokerFactory::GetInstance().CreateInvoker("org.deepin.PermissionManager",
                                                                           "/org/deepin/PermissionManager/PolicyManager",
                                                                           "org.deepin.PermissionManager.PolicyManager",
                                                                           ConnectType::SYSTEM, this);
    // 重启服务接口
    m_rootSystemDBusInter = InvokerFactory::GetInstance().CreateInvoker("com.deepin.SessionManager",
                                                                        "/com/deepin/SessionManager",
                                                                        "com.deepin.SessionManager",
                                                                        ConnectType::SESSION, this);
}

// 系统安全等级按钮是否显示
bool SecurityToolsModel::isShowSystemLevelUi()
{
    m_isLevelShow = m_gsetting->GetValue(SYSTEM_SAFE_LEVEL_SHOW).toBool();
    if (SYSTEM_SAFE_LEVEL_STATUS_OPEN == m_sLevelStatus || m_isLevelShow) {
        if (m_isValidSecurityEnhance) {
            return true;
        }
    }

    return false;
}

bool SecurityToolsModel::isAllowExeFilesProtection()
{
    bool isExeFilesDisplay = false;
    if (SYSTEM_SAFE_LEVEL_STATUS_OPEN == m_sLevelStatus) {
        struct passwd *pws;
        pws = getpwuid(getuid());
        QString currentUserName = QString(pws->pw_name);
        if (currentUserName == SYSTEM_SAFE_LEVEL_SECADM_NAME) {
            isExeFilesDisplay = true;
        } else {
            DDialog dialog;
            dialog.setMinimumSize(QSize(TIP_DIALOG_WIDTH, TIP_DIALOG_HEIGHT));
            dialog.setMaximumSize(QSize(TIP_DIALOG_WIDTH, TIP_DIALOG_HEIGHT));
            dialog.setIcon(QIcon::fromTheme("deepin-defender"));
            dialog.setMessage(tr("You have enabled privilege separation, and only the security admin can configure it. Please switch user accounts and try again. "));
            dialog.setModal(true);
            dialog.setWordWrapMessage(true);
            dialog.addButton(tr("OK", "Button"), false);

            dialog.exec();
        }
    } else {
        // 获取当前用户uid
        unsigned int currentUid = getuid();
        // 获取系统用户路径
        QVariantList args = DBUS_BLOCK_INVOKE(m_accountsDBusInter, "ListCachedUsers").arguments();
        if (!args.isEmpty()) {
            QVariant var = args.first();
            QDBusArgument ba = var.value<QDBusArgument>();
            QList<QString> sTypeList;
            ba >> sTypeList;

            for (int i = 0; i < sTypeList.count(); i++) {
                if (sTypeList.at(i).contains(QString::number(currentUid))) {
                    DBusInvokerInterface *user;
                    if (m_accountInterMap[sTypeList.at(i)]) {
                        user = m_accountInterMap[sTypeList.at(i)];
                    } else {
                        user = InvokerFactory::GetInstance().CreateInvoker("org.freedesktop.Accounts",
                                                                           sTypeList.at(i),
                                                                           "org.freedesktop.Accounts.User",
                                                                           ConnectType::SYSTEM, this);

                        m_accountInterMap[sTypeList.at(i)] = user;
                    }

                    QVariantList argsUser = DBUS_BLOCK_INVOKE(user, DBUS_PROPERTY_INVOKER_NAME, "AccountType").arguments();
                    if (!args.isEmpty()) {
                        QVariant varUser = argsUser.first();
                        QDBusVariant dbvFirstUser = varUser.value<QDBusVariant>();
                        QVariant vFirstUser = dbvFirstUser.variant();
                        int nType = vFirstUser.toInt();
                        if (1 == nType) {
                            isExeFilesDisplay = true;
                        } else {
                            DDialog dialog;
                            dialog.setMinimumSize(QSize(TIP_DIALOG_WIDTH, TIP_DIALOG_HEIGHT));
                            dialog.setMaximumSize(QSize(TIP_DIALOG_WIDTH, TIP_DIALOG_HEIGHT));
                            dialog.setIcon(QIcon::fromTheme("deepin-defender"));
                            dialog.setModal(true);
                            dialog.setMessage(tr("Only the administrator can configure it. Please switch user accounts and try again."));
                            dialog.setWordWrapMessage(true);
                            dialog.addButton(tr("OK", "Button"), false);

                            dialog.exec();
                        }
                    }
                }
            }
        }
    }

    return isExeFilesDisplay;
}
